﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Constriction.Constrict
{
    public class ConstrictPoint
    {
        public static float MinDistanceToTarget;
        public static float ConstrictTime;//Num of seconds to reach target
        public static float WiggleTime;

        private Vector2 origPosition;
        private Vector2 curPosition;
        private Vector2 drawPosition;
        private Vector2 wiggleTarget;

        private Vector2 velocity;
        private Vector2 wiggleVelocity;

        public bool waitingAtOrigPosition;
        public bool isWiggling;
        private bool movingTowardsTarget;

        public ConstrictPoint(Vector2 position)
        {
            origPosition = position;
            curPosition = position;
            drawPosition = position;

            velocity = Vector2.Zero;

            waitingAtOrigPosition = true;
            isWiggling = false;
            movingTowardsTarget = true;
        }

        public void Update(GameTime time, Vector2 target)
        {
            if (!waitingAtOrigPosition)
            {
                if (movingTowardsTarget)
                {
                    UpdateVelocity(target, MinDistanceToTarget);
                    MoveTowardsTarget(time, target);
                    CheckTarget(target);
                }
                else
                {
                    UpdateVelocity(origPosition, 0);
                    MoveTowardsTarget(time, origPosition);
                    CheckOrigPosition();
                }

                UpdateWiggle(time);
            }
        }

        private void UpdateVelocity(Vector2 target, float stopAt)
        {
            if (velocity == Vector2.Zero)
            {
                float distance = Vector2.Distance(curPosition, target);
                distance -= stopAt;
                float distancePerSecond = distance / ConstrictTime;

                velocity = target - curPosition;
                velocity.Normalize();
                velocity *= distancePerSecond;
            }
        }

        private void MoveTowardsTarget(GameTime time, Vector2 target)
        {
            curPosition += velocity * (float)time.ElapsedGameTime.TotalSeconds;
        }

        private void CheckTarget(Vector2 target)
        {
            if (Vector2.Distance(curPosition, target) < MinDistanceToTarget)
            {
                movingTowardsTarget = !movingTowardsTarget;
                velocity = Vector2.Zero;
            }
        }

        private void CheckOrigPosition()
        {
            if (Vector2.Distance(curPosition, origPosition) < 1)
            {
                movingTowardsTarget = !movingTowardsTarget;
                velocity = Vector2.Zero;
                waitingAtOrigPosition = true;
            }
        }

        public void StartWiggling(Vector2 target, bool wiggleTowardsTarget)
        {
            drawPosition = curPosition;

            if (wiggleTowardsTarget)
            {
                wiggleTarget = target;
            }
            else
            {
                var newWiggleTarget = origPosition - curPosition;
                newWiggleTarget = new Vector2(newWiggleTarget.X * 0.8f, newWiggleTarget.Y * 0.8f);
                wiggleTarget = curPosition + newWiggleTarget;
            }

            wiggleVelocity = wiggleTarget - curPosition;
            wiggleVelocity.Normalize();
            wiggleVelocity *= WiggleTime;
            isWiggling = true;
        }

        private void UpdateWiggle(GameTime time)
        {
            //TODO Smooth animation when retracting wiggle

            if (isWiggling)
            {
                if (Vector2.Distance(drawPosition, wiggleTarget) < 32)
                {
                    isWiggling = false;
                    drawPosition = curPosition;
                }
                else
                {
                    drawPosition += wiggleVelocity * (float)time.ElapsedGameTime.TotalSeconds;
                }
            }
            else
            {
                drawPosition = curPosition;
            }
        }

        public void Draw(SpriteBatch batch)
        {
            batch.Draw(MainGame.emptyTex, curPosition, Color.Black);
            batch.Draw(MainGame.emptyTex, new Rectangle((int)wiggleTarget.X, (int)wiggleTarget.Y, 5, 5), Color.Red);
            batch.Draw(MainGame.emptyTex, new Rectangle((int)drawPosition.X, (int)drawPosition.Y, 5, 5), Color.Green);
        }

        public Vector2 DrawPosition { get { return drawPosition; } }
        public Vector2 OrigPosition { get { return origPosition; } }
    }
}
